// Copyright 2019 The rhyme_lph Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// P [author] rhyme_lph
// S [email]  rhymelph@gmail.com
// I [github] https://github.com/rhymelph

import 'dart:convert';
import 'dart:io';

import 'package:base_plugin/base_plugin.dart';
import 'package:dio/dio.dart';
import 'package:finance_app/generated/l10n.dart';
import 'package:finance_app/src/common/config.dart';
import 'package:finance_app/src/entities/biometrics_data_entity.dart';
import 'package:finance_app/src/entities/company_entity.dart';
import 'package:finance_app/src/entities/my_invitations_entity.dart';
import 'package:finance_app/src/entities/user_profile_entity.dart';
import 'package:finance_app/src/http_service/http_company_service.dart';
import 'package:finance_app/src/http_service/http_invitation_service.dart';
import 'package:finance_app/src/http_service/http_login_service.dart';
import 'package:finance_app/src/http_service/http_user_service.dart';
import 'package:finance_app/src/router_gen/router_gen_providers.dart';
import 'package:finance_app/src/widgets/bottom_sheet/delete_info_bottom_sheet.dart';
import 'package:flutter/material.dart';
import 'package:local_auth/local_auth.dart';
import 'package:onesignal_flutter/onesignal_flutter.dart';

class LoginProvider extends BaseProvider {
  final TextEditingController phoneController = TextEditingController();
  FocusNode phoneFocusNode = FocusNode();

  TextEditingController emailController = TextEditingController();
  FocusNode emailFocusNode = FocusNode();

  TextEditingController passwordController = TextEditingController();
  FocusNode passwordFocusNode = FocusNode();

  bool enable = false;

  bool passwordError = false;

  bool enableAuth = false;

  String countryCode = "+65";

  String currentType = S.current.email;

  bool loginFailed;

  @override
  void dispose() {
    super.dispose();
    passwordController.dispose();
    phoneFocusNode.dispose();
    phoneController.dispose();
    emailFocusNode.dispose();
    emailController.dispose();
    passwordFocusNode.dispose();
  }

  @override
  void initState() {
    super.initState();

    phoneController.addListener(_onUpdateInput);
    passwordController.addListener(_onUpdateInput);

    _checkEnableAuth();
  }

  void _onUpdateInput() {
    if (currentType == S.current.email) {
      if (emailController.text.length > 0) {
        if (enable == false) {
          enable = true;
          update();
        }
      } else {
        if (enable == true) {
          enable = false;
          update();
        }
      }
    } else {
      if (phoneController.text.length > 0) {
        if (enable == false) {
          enable = true;
          update();
        }
      } else {
        if (enable == true) {
          enable = false;
          update();
        }
      }
    }
  }

  void unFocus() {
    phoneFocusNode.unfocus();
    passwordFocusNode.unfocus();
  }

  void onChangeType(String e) {
    if (currentType == e) return;
    currentType = e;
    _onUpdateInput();
    update();
  }

  void onLogin() async {
    unFocus();
    String phone = phoneController.text;
    String email = emailController.text;
    String password = passwordController.text;
    bool isSuccess = false;
    obtainContext?.call((context) async {
      BaseConfig.dialogBase
          .showLoadingDialog(context: context, text: 'Loading');

      if (Config.pushKey == null) {
        final state = await OneSignal.shared.getDeviceState();
        RProvider.myProvider.globalMap[ConfigKey.pushKey] = state.userId;
        await RProvider.myProvider.updateGlobalMap();
      }
      if (currentType == S.current.email) {
        await post(HttpLoginService.loginByEmail(email, null, password),
            onSuccess: (result) async {
          isSuccess = true;
          RProvider.myProvider.globalMap[ConfigKey.token] =
              result.data[BaseConfig.presenterBase.dataKey]['token'];
          RProvider.myProvider.globalMap[ConfigKey.biometrics] =
              base64.encode(json.encode({
            'account': phone,
            'countryCode': countryCode,
            'password': password,
          }).codeUnits);
        }, onError: (int statusCode, String msg, Object error,
                StackTrace stackTrace) {
          loginFailed = false;
          update();
        });
      } else {
        await post(HttpLoginService.login(countryCode, phone, null, password),
            onSuccess: (result) async {
          isSuccess = true;
          RProvider.myProvider.globalMap[ConfigKey.token] =
              result.data[BaseConfig.presenterBase.dataKey]['token'];
          RProvider.myProvider.globalMap[ConfigKey.biometrics] =
              base64.encode(json.encode({
            'account': phone,
            'countryCode': countryCode,
            'password': password,
          }).codeUnits);
        }, onError: (int statusCode, String msg, Object error,
                StackTrace stackTrace) {
          loginFailed = false;
          update();
        });
      }

      if (isSuccess) {
        await post(HttpCompanyService.companyList(), onSuccess: (result) async {
          List<CompanyEntity> companies =
              getEntityFromResult<List<CompanyEntity>>(result);
          if (companies.length == 0) {
            Navigator.of(context).pop();
            await post(HttpUserService.getMyProfile(),
                autoHandler: AutoHandler.Toast, onSuccess: (result) async {
              RProvider.myProvider.globalMap[ConfigKey.userProfile] =
                  getEntityFromResult<UserProfileEntity>(result);
            });
            showNoActiveCompanyBottomSheet(
              context,
              onDelete: () {
                Routes.navigateTo(RouterGenProviders.createBusinessProfilePage,
                    clearStack: true);
              },
            );
          } else {
            afterLoginAction();
          }
        });
      } else {
        Navigator.of(context).pop();
      }
    });
  }

  Future<void> afterLoginAction() async {
    await RProvider.myProvider.updateGlobalMap();

    //获取邀请
    await post(HttpInvitationService.myInvitation(),
        autoHandler: AutoHandler.Toast, onSuccess: (result) async {
      RProvider.myProvider.globalMap[ConfigKey.myInvitations] =
          getEntityFromResult<List<MyInvitationsEntity>>(result);
      if (Config.myInvitations.length == 0) {
        RProvider.myProvider.globalMap[ConfigKey.myInvitations] = null;
      }
      await RProvider.myProvider.updateGlobalMap();
    });
    //获取用户信息
    await post(HttpUserService.getMyProfile(), autoHandler: AutoHandler.Toast,
        onSuccess: (result) async {
      RProvider.myProvider.globalMap[ConfigKey.userProfile] =
          getEntityFromResult<UserProfileEntity>(result);
      await RProvider.myProvider.updateGlobalMap();
    });
    if (Config.myInvitations != null) {
      Routes.navigateTo(RouterGenProviders.pendingInvitationPage,
          clearStack: true);
    } else if (Config.userProfile.name == null) {
      Routes.navigateTo(RouterGenProviders.createAccountPage, clearStack: true);
    } else if (Config.userProfile.defaultCompanyId == null) {
      Routes.navigateTo(RouterGenProviders.createBusinessProfilePage,
          clearStack: true);
    } else {
      Routes.navigateTo(RouterGenProviders.dashboardPage, clearStack: true);
    }
  }

  @override
  Future get dataFuture => null;

  void onNavRegister() {
    unFocus();
    Routes.navigateTo(RouterGenProviders.registerPage);
  }

  void onNavFreeDemo() {
    unFocus();
    Routes.navigateTo(RouterGenProviders.requestFreeDemoPage);
  }

  void onNavForgotPassword() {
    unFocus();
    Routes.navigateTo(RouterGenProviders.forgotPasswordPage);
  }

  void _checkEnableAuth() async {
    enableAuth = await LocalAuthentication().canCheckBiometrics;
    update();
  }

  void onFingerLogin() async {
    //指纹的登录
    final data = await LocalAuthentication()
        .authenticate(localizedReason: S.current.please_touch_fingerprint);
    if (data == true) {
      BiometricsDataEntity bioData = Config.biometricsData;
      if (bioData != null) {
        countryCode = bioData.countryCode;
        phoneController.text = bioData.account;
        passwordController.text = bioData.password;
      }
      update();
      onLogin();
    }
  }

  void onChangeCountryCode(value) {
    if (value != countryCode) countryCode = value;
  }
}
